﻿using System;
using jade.core;
using jade.core.behaviours;
using jade.lang.acl;
using jade.domain.FIPAAgentManagement;
using jade.domain;
using jade.content;
using log4net;
using jade.content.lang;
using jade.content.onto;
using Agents.ontology;
using jade.content.lang.leap;
using GatewayUtil.gatewayConfig;
using Action = jade.content.onto.basic.Action;
using Result = jade.content.onto.basic.Result;

namespace Agents
{
    class HashMasterAgent : Agent
    {
        protected static readonly ILog log = LogManager.GetLogger(typeof(HashMasterAgent));
        private Codec codec = new LEAPCodec();
        //public Codec codec = new SLCodec();
        private Ontology ontology = HashMasterOntology.getInstance();

        public override void setup()
        {

            log.Debug("Start Agent with name: " + this.getLocalName());
            getContentManager().registerLanguage(codec);
            getContentManager().registerOntology(ontology);
            getContentManager().registerOntology(FIPAManagementOntology.getInstance());


            addBehaviour(new ReceiverBehaviour(this));

            ServiceDescription sd = new ServiceDescription();
            sd.setName(this.getLocalName());
            sd.setType("HashMasterAgent");
            sd.addOntologies(ontology.getName());

            
            // make agent publicable as webservice
            sd.addProperties(new Property(GWConst.PUBLIC_AS_WEBSERVICE,true));
            sd.addProperties(new Property(GWConst.OPERATION, "HashMasterOntology.Agents.HashRequest"));

            DFAgentDescription dfad = new DFAgentDescription();
            dfad.setName(this.getAID());
            dfad.addServices(sd);
            DFService.register(this, dfad);
        }

        private void debug(string p)
        {
            log.Debug(this.getLocalName() + ": " + p);

        }
        private void error(string p)
        {
            log.Error(this.getLocalName() + ": " + p);

        }
        private void error(object p)
        {
            log.Error(this.getLocalName() + ": " + p);

        }

        public override void takeDown()
        {
            base.takeDown();
            try
            {
                DFService.deregister(this);
            }
            catch (FIPAException e)
            {
                error(e);
            }

        }

        class ReceiverBehaviour : CyclicBehaviour
        {
            private Codec codec = new LEAPCodec();
            //public Codec codec = new SLCodec();
            private Ontology ontology = HashMasterOntology.getInstance();
            private MessageTemplate template = MessageTemplate.MatchOntology(HashMasterOntology.getInstance().getName());
            public ReceiverBehaviour(Agent a)
                : base(a)
            {

            }

            public override void action()
            {
                try
                {
                    ((HashMasterAgent)this.myAgent).debug("receiver: waiting for message");
                    ACLMessage msg = this.myAgent.receive(template);
                    if (msg != null)
                    {
                        this.myAgent.getContentManager().setValidationMode(false);
                        Action action = (Action)this.myAgent.getContentManager().extractContent(msg);
                        AgentAction agentAction = (AgentAction)action.getAction();
                        HashResponse hashResponse = null;

                        if (agentAction is HashRequest)
                        {
                            hashResponse = performHashRequest((HashRequest)agentAction);
                        }                        
                        else
                        {
                            // error state
                            log.Error("AgentAction is not valid, its type is " + agentAction.GetType().FullName);
                        }
                        Result result = new Result(action,hashResponse);
                        ContentElement content = result;

                        ACLMessage reply = msg.createReply();
                        reply.setPerformative(ACLMessage.INFORM);

                        this.myAgent.getContentManager().fillContent(reply, content);                        
                        reply.addUserDefinedParameter(ACLMessage.IGNORE_FAILURE, "true");

                        ((HashMasterAgent)this.myAgent).debug("Sending response");
                        this.myAgent.send(reply);
                        ((HashMasterAgent)this.myAgent).debug("The message was successfully sent back");

                    }
                    else block();
                }
                catch (System.Exception e)
                {
                    ((HashMasterAgent)this.myAgent).error(e);
                    throw e;
                }
            }



            private HashResponse performHashRequest(HashRequest hashRequest)
            {
                log.Debug("hashRequest operation");
                HashResponse response = new HashResponse();
                response.setHashMethod(hashRequest.getHashMethod());
                /* Read the initial time. */
                DateTime startTime = DateTime.Now;


                response.setText(getMD5Hash(hashRequest.getText()));

                
                DateTime stopTime = DateTime.Now;
                /* Compute the duration between the initial and the end time. */
                TimeSpan duration = stopTime - startTime;
                
                response.setSpentTime(duration.Milliseconds);

                return response;

            }

            public string getMD5Hash(string input)
            {
                System.Security.Cryptography.MD5CryptoServiceProvider md5Provider = new System.Security.Cryptography.MD5CryptoServiceProvider();
                byte[] bs = System.Text.Encoding.UTF8.GetBytes(input);
                bs = md5Provider.ComputeHash(bs);
                System.Text.StringBuilder s = new System.Text.StringBuilder();
                foreach (byte b in bs)
                {
                    s.Append(b.ToString("x2").ToLower());
                }
                string password = s.ToString();
                return password;
            }




        }

    }
}
